package net.kesumu.yushabu;

import java.net.URI;
import java.net.URLEncoder;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import net.kesumu.general.android.view.CustomStatusBar;
import net.kesumu.yushabu.storage.YushabuMessageContract;
import net.kesumu.yushabu.storage.YushabuMessageDbOperator;
import net.kesumu.yushabu.storage.YushabuSessionDbOperator;
import net.kesumu.yushabu.testing.MessagesListAdapter;
import net.kesumu.yushabu.utils.JSONUtil;
import net.kesumu.yushabu.utils.WsConfig;
import net.kesumu.yushabuserver.entity.Message;
import net.kesumu.yushabuserver.entity.YushabuMessage;
import net.kesumu.yushabuserver.entity.YushabuSession;

import org.json.JSONException;
import org.json.JSONObject;

import com.codebutler.android_websockets.WebSocketClient;
import com.umeng.message.PushAgent;

import net.kesumu.yushabu.R;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActionBar;
import android.app.Fragment;
import android.app.ListFragment;
import android.content.Intent;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;


/**
 * This activity contains work refer to others
 * The original class I got from url below:
 * http://www.androidhive.info/2014/10/android-building-group-chat-app-using-sockets-part-2/
 * @author Z 2014-12-19
 *
 */
public class MessagingActivity extends Activity {
    
    public static final String TYPE_SINGLE_CHAT = "type_single_chat",
                               TYPE_GROUP_CHAT = "type_group_chat";
    
    public static final String STATE_IN_ROOM = "state_in_room",
                               STATE_NOT_IN_ROOM = "state_not_in_room";

    // LogCat tag
    private static final String TAG = MainActivity.class.getSimpleName();
 
    private Button mSendBtn;
    private EditText mTextMessageView;
 
    
 
    // Chat messages list adapter
    private MessagesListAdapter adapter;
    private List<Message> listMessages;
    private ListView listViewMessages;
 
    private ArrayList<YushabuMessage> mYushabuMessageList;
    private YushabuMessageAdapter mYushabuMessageAdatper;
    private ListView mYushabuMessageListView;
 
    private String type;
    private String state;
    // Client name
    private String mChatId;
    private String mMyId;
    private String mYushabuSessionId;
    private String mFriendId;
    private String mFriendName;
    private String mMessage;
 
    // JSON flags to identify the kind of JSON response
    private static final String TAG_SELF = "self", TAG_NEW = "new",
            TAG_MESSAGE = "message", TAG_EXIT = "exit";

    
    @SuppressWarnings("deprecation")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_messaging);
        getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); 
        getActionBar().setCustomView(R.layout.actionbar);
        ((TextView)findViewById(R.id.actionbar_title)).setText(getString(R.string.title_activity_messaging));
      //Custom the status bar
        CustomStatusBar customStatusBar = new CustomStatusBar(this);
        customStatusBar.setStatusBarColor(findViewById(R.id.statusBarBackground), getResources().getColor(R.color.main));

        
        
        if (savedInstanceState == null) {
            getFragmentManager().beginTransaction()
                    .add(R.id.container, new YushabuMessageFragment()).commit();
        }
        
        // Getting the person name from previous screen
        Intent i = getIntent();
        type = i.getStringExtra("type");
        state = i.getStringExtra("state");
        mMyId = i.getStringExtra("myId");
        mYushabuSessionId = i.getStringExtra("yushabuSessionId");
        mFriendId = i.getStringExtra("friendId");
        mFriendName = i.getStringExtra("friendName");
        mChatId = i.getStringExtra("chatId");
        
        if(type != null && type.equals(TYPE_SINGLE_CHAT)) {
            ((TextView)findViewById(R.id.actionbar_title)).setText(mFriendName);
        }

//        if (savedInstanceState == null) {
//            getFragmentManager().beginTransaction()
//                    .add(R.id.container, new PlaceholderFragment()).commit();
//        }
        
//        //temporary set style of action bar
//        ActionBar actionBar = getActionBar();
//        actionBar.setDisplayShowHomeEnabled(false);
        

        
//        listViewMessages = (ListView) findViewById(R.id.list_view_messages);
//        listMessages = new ArrayList<Message>();
//        adapter = new MessagesListAdapter(this, listMessages);
//        
//        listViewMessages.setAdapter(adapter);
 
        startUpClient();
        
        PushAgent.getInstance(this).onAppStart();
    }
    
    @Override
    protected void onStart() {
        super.onStart();
        mSendBtn = (Button) findViewById(R.id.btn_send);
        
        mTextMessageView = (EditText) findViewById(R.id.text_message);
        mTextMessageView.setImeActionLabel(getResources().getString(R.string.btn_send), 
                                                            KeyEvent.KEYCODE_ENTER);
        mTextMessageView.setOnEditorActionListener(new OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                boolean handled = false;
                if (actionId == EditorInfo.IME_ACTION_DONE) {
                    send(mSendBtn);
                    handled = true;
                }
                return handled;
            }
            
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.messaging, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
//        if (id == R.id.action_settings) {
//            return true;
//        }
        return super.onOptionsItemSelected(item);
    }
    
    public void send(View clickedView) {
        mMessage = mTextMessageView.getText().toString();
        if(mMessage == null || mMessage.equals("")) {
            return;
        }
        if(type.equalsIgnoreCase(TYPE_SINGLE_CHAT)) {
            // Sending message to web socket server
            sendRequest(jsonUtil.getSendMessageSingleJSON(mMyId, mFriendId, mMessage));
        }else if(type.equalsIgnoreCase(TYPE_GROUP_CHAT)) {
         // Sending message to web socket server
            sendRequest(jsonUtil.getSendMessageGroupJSON(mMyId, mChatId, mMessage));
        }
        // Clearing the input filed once message was sent
        mTextMessageView.setText("");
    }
    
    public void setupSingleChatRoom() {
        if(state.equals(STATE_NOT_IN_ROOM)) {
            YushabuSessionDbOperator yushabuSessionDbOperator = 
                                    new YushabuSessionDbOperator(getApplicationContext());
            YushabuSession selectedYushabuSession = 
                                yushabuSessionDbOperator.selectByFriendIdAndSessionId(mFriendId, "0");
            if(selectedYushabuSession == null) {
                YushabuSession yushabuSession = new YushabuSession(
                                                Integer.parseInt(mFriendId), mFriendName);
                yushabuSessionDbOperator.insert(yushabuSession);
            }
            state = STATE_IN_ROOM;
        }
    }
    
    public void storeMessage(YushabuMessage yushabuMessage) {
        YushabuMessageDbOperator yushabuMessageDbOperator = 
                                    new YushabuMessageDbOperator(getApplicationContext());
        YushabuMessage selectedMessage = 
                yushabuMessageDbOperator.selectByMessageId(yushabuMessage.getMessageId()+"");
        if(selectedMessage == null) {
            yushabuMessageDbOperator.insert(yushabuMessage);
        }
    }
    
    private void readMessageListFromLocalDatabase() {
        LocalMessageListReader localMessageListReader = new LocalMessageListReader();
        localMessageListReader.execute("");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
         
        if(client != null & client.isConnected()){
            client.disconnect();
        }
    }
    
    private WebSocketClient client;
    private JSONUtil jsonUtil;
    void startUpClient() {
        jsonUtil = new JSONUtil(getApplicationContext());
        /**
         * Creating web socket client. This will have callback methods
         * */
        client = new WebSocketClient(URI.create(WsConfig.URL_WEBSOCKET
                + URLEncoder.encode(WsConfig.SESSION_TAG_MESSAGE + ":" + mMyId)), new WebSocketClient.Listener() {
            public void onConnect() {
 
            }
 
            /**
             * On receiving the message from web socket server
             * */
            public void onMessage(String message) {
                Log.d(TAG, String.format("Got string message! %s", message));
 
                parseMessage(message);
 
            }
 
            public void onMessage(byte[] data) {
                Log.d(TAG, String.format("Got binary message! %s",
                        bytesToHex(data)));
 
                // Message will be in JSON format
                parseMessage(bytesToHex(data));
            }
 
            /**
             * Called when the connection is terminated
             * */
            public void onDisconnect(int code, String reason) {
 
                String message = String.format(Locale.US,
                        "Disconnected! Code: %d Reason: %s", code, reason);
 
                showToast(message);
 
                // clear the session id from shared preferences
                jsonUtil.storeSessionId(null);
            }
 
            public void onError(Exception error) {
                Log.e(TAG, "Error! : " + error);
 
                showToast("Error! : " + error);
            }
 
        }, null);
 
        client.connect();
    }
    /**
     * Method to send message to web socket server
     * */
    private void sendRequest(String message) {
        if (client != null && client.isConnected()) {
            client.send(message);
        }
    }

    /**
     * Parsing the JSON message received from server The intent of message will
     * be identified by JSON node 'flag'. flag = self, message belongs to the
     * person. flag = new, a new person joined the conversation. flag = message,
     * a new message received from server. flag = exit, somebody left the
     * conversation.
     * */
    private void parseMessage(final String msg) {
 
        try {
            JSONObject jObj = new JSONObject(msg);
 
            // JSON node 'flag'
            String flag = jObj.getString("flag");
 
            // if flag is 'self', this JSON contains session id
            if (flag.equalsIgnoreCase(JSONUtil.FLAG_MESSAGE_SINGLE_SOURCE)) {
 
//                String sessionId = jObj.getString("sessionId");
// 
//                // Save the session id in shared preferences
//                jsonUtil.storeSessionId(sessionId);
// 
//                Log.e(TAG, "Your session id: " + jsonUtil.getSessionId());
                String result = jObj.getString("result");
                showToast(result);
                if(result != null && result.equalsIgnoreCase("success")) {
                    
                    String messageId = jObj.getString("messageId");
                    String userId = jObj.getString("userId");
                    String friendId = jObj.getString("friendId");
                    String content = jObj.getString("content");
                    String sendTime = jObj.getString("sendTime");
                    
                    final YushabuMessage receivedMessage = new YushabuMessage();
                    receivedMessage.setMessageId(Integer.parseInt(messageId));
                    receivedMessage.setUserId(Integer.parseInt(userId));
                    receivedMessage.setFriendUserId(Integer.parseInt(friendId));
                    receivedMessage.setContent(content);
                    receivedMessage.setSendTime(Timestamp.valueOf(sendTime));
                    receivedMessage.setSessionId(0);
                    receivedMessage.setState(YushabuMessageContract.STATE_READED);
                    
                    setupSingleChatRoom();
                    storeMessage(receivedMessage);
                    
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            mYushabuMessageAdatper.addItem(receivedMessage);
                       }
                    });
                }
 
            } else if(flag.equalsIgnoreCase(JSONUtil.FLAG_MESSAGE_SINGLE_DESTINATION)) {
                String friendId = jObj.getString("friendId");
                String messageId = jObj.getString("messageId");
                String userId = jObj.getString("userId");
                String content = jObj.getString("content");
                String sendTime = jObj.getString("sendTime");
                final YushabuMessage receivedMessage = new YushabuMessage();
                receivedMessage.setMessageId(Integer.parseInt(messageId));
                receivedMessage.setUserId(Integer.parseInt(userId));
                receivedMessage.setFriendUserId(Integer.parseInt(friendId));
                receivedMessage.setContent(content);
                receivedMessage.setSendTime(Timestamp.valueOf(sendTime));
                receivedMessage.setSessionId(0);
                receivedMessage.setState(YushabuMessageContract.STATE_READED);
                
                setupSingleChatRoom();
                storeMessage(receivedMessage);
                
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mYushabuMessageAdatper.addItem(receivedMessage);
                   }
                });
                
                sendRequest(jsonUtil.getReceiveMessageSingleJSON(messageId));
            }
            
            /*else if (flag.equalsIgnoreCase(TAG_NEW)) {
                // If the flag is 'new', new person joined the room
                String name = jObj.getString("name");
                String message = jObj.getString("message");
 
                // number of people online
                String onlineCount = jObj.getString("onlineCount");
 
                showToast(name + message + ". Currently " + onlineCount
                        + " people online!");
 
            } else if (flag.equalsIgnoreCase(TAG_MESSAGE)) {
                // if the flag is 'message', new message received
                String fromName = mMyId;
                String message = jObj.getString("message");
                String sessionId = jObj.getString("sessionId");
                boolean isSelf = true;
 
                // Checking if the message was sent by you
                if (!sessionId.equals(jsonUtil.getSessionId())) {
                    fromName = jObj.getString("name");
                    isSelf = false;
                }
 
                Message m = new Message(fromName, message, isSelf);
 
                // Appending the message to chat list
                appendMessage(m);
 
            } else if (flag.equalsIgnoreCase(TAG_EXIT)) {
                // If the flag is 'exit', somebody left the conversation
                String name = jObj.getString("name");
                String message = jObj.getString("message");
 
                showToast(name + message);
            }*/
 
        } catch (JSONException e) {
            e.printStackTrace();
        }
 
    }
    
    /**
     * Appending message to list view
     * */
    private void appendMessage(final Message m) {
        runOnUiThread(new Runnable() {
            public void run() {
                listMessages.add(m);
                adapter.notifyDataSetChanged();
                // Playing device's notification
                playBeep();
            }
        });
    }

    private void showToast(final String message) {
        runOnUiThread(new Runnable() {
 
            public void run() {
                Toast.makeText(getApplicationContext(), message,
                        Toast.LENGTH_LONG).show();
            }
        });
    }

    /**
     * Plays device's default notification sound
     * */
    public void playBeep() {
        try {
            Uri notification = RingtoneManager
                    .getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
            Ringtone r = RingtoneManager.getRingtone(getApplicationContext(),
                    notification);
            r.play();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
    
    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    /**
     * define the ChatAdapter class for chat list
     * @author Z 2014-12-16
     *
     */
    private class YushabuMessageAdapter extends BaseAdapter{
        ArrayList<YushabuMessage> yushabuMessageList = new ArrayList<YushabuMessage>();
        
        public void setData(ArrayList<YushabuMessage> cl) {
            this.yushabuMessageList = cl;
            this.notifyDataSetChanged();
        }
        public int getCount() {
            if(yushabuMessageList == null) {
                return 0;
            }else {
                return yushabuMessageList.size();
            }
        }
        public Object getItem(int position) {
            if(yushabuMessageList == null) {
                return null;
            }else{
                YushabuMessage yushabuMessage = yushabuMessageList.get(position);
                return yushabuMessage;
            }
        }
        public long getItemId(int position) {
            return position;
        }
        public View getView(int position, View convertView, ViewGroup parent) {

            /**
             * The following list not implemented reusable list items as list items
             * are showing incorrect data Add the solution if you have one
             * */
     
            YushabuMessage yushabuMessage = yushabuMessageList.get(position);
     
            // Identifying the message owner
            if (yushabuMessage.getUserId() == Integer.parseInt(mMyId)) {
                // message belongs to you, so load the right aligned layout
                convertView = getLayoutInflater().inflate(R.layout.list_item_message_right,
                        null);
            } else {
                // message belongs to other person, load the left aligned layout
                convertView = getLayoutInflater().inflate(R.layout.list_item_message_left,
                        null);
            }
     
//            TextView lblFrom = (TextView) convertView.findViewById(R.id.lblMsgFrom);
//            lblFrom.setText(m.getFromName());
            
            TextView txtMsg = (TextView) convertView.findViewById(R.id.txtMsg);
            txtMsg.setText(yushabuMessage.getContent());
            
            return convertView;
        }
        
        public void addItem(final YushabuMessage item) {
            yushabuMessageList.add(item);
            notifyDataSetChanged();
        }
    }
    
    /**
     * define the chat fragment for chat list
     * @author Z 2014-12-16
     *
     */
    @SuppressLint("ValidFragment")
    private class YushabuMessageFragment extends ListFragment {   
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View fragment = inflater.inflate(R.layout.fragment_messaging, container, false);
            mYushabuMessageAdatper = new YushabuMessageAdapter();
            readMessageListFromLocalDatabase();
            setListAdapter(mYushabuMessageAdatper);
            return fragment;
        }
        
        @Override
        public void onListItemClick(ListView l, View v, int position, long id) {
            super.onListItemClick(l, v, position, id);
            
        }
    }

    private class LocalMessageListReader extends AsyncTask<String, Integer, ArrayList<YushabuMessage>>{
        @Override
        protected ArrayList<YushabuMessage> doInBackground(String... arg0) {
            ArrayList<YushabuMessage> selectedMessages = null;
            YushabuMessageDbOperator yushabuMessageDbOperator = new YushabuMessageDbOperator(getApplicationContext());
            if(type.equals(TYPE_SINGLE_CHAT)) {
                selectedMessages =  yushabuMessageDbOperator.selectAllByFriendId(mFriendId);
            }else {
                selectedMessages = yushabuMessageDbOperator.selectAllBySessionId(mYushabuSessionId);
            }
            for(int i=0;i<selectedMessages.size();i++) {
                if(selectedMessages.get(i).getState() == YushabuMessageContract.STATE_UNREADED) {
                    yushabuMessageDbOperator.updateReadedMessageByMessageId(
                            selectedMessages.get(i).getMessageId()+"");
                }
            }
            return selectedMessages;
        }
        
        @Override
        protected void onPostExecute(ArrayList<YushabuMessage> result) {
            super.onPostExecute(result);
            mYushabuMessageList = result;
            mYushabuMessageAdatper.setData(mYushabuMessageList);
        }
        
    } 

}
